package sf_time

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"lib/memory"
	"regexp"
	"slices"
	"sort"
	"strconv"
	"strings"
	"time"
)

// FormatMinutes 转换分钟为时间格式
func FormatMinutes(minutes int) string {
	// 将分钟转换为小时和分钟
	hours := minutes / 60
	minutes %= 60

	return fmt.Sprintf("%02dh%02dm", hours, minutes)
}

func CalcDurationMinutes(isDomestic bool, depAirportCode, depTime, arrAirportCode, arrTime string) (string, error) {
	if isDomestic || depAirportCode == arrAirportCode {
		return calcLocalDurationMinutes(depTime, arrTime)
	}

	oTime, err := parseAirportLocalTime(depAirportCode, depTime)
	if err != nil {
		return "", err
	}
	aTime, err := parseAirportLocalTime(arrAirportCode, arrTime)
	if err != nil {
		return "", err
	}

	return FormatMinutes(int(aTime.Sub(*oTime).Minutes())), nil
}

func calcLocalDurationMinutes(depTime, arrTime string) (string, error) {
	t, err := time.Parse("2006-01-02 15:04", depTime)
	if err != nil {
		return "", err
	}
	t2, err := time.Parse("2006-01-02 15:04", arrTime)
	if err != nil {
		return "", err
	}

	return FormatMinutes(int(t2.Sub(t).Minutes())), nil
}

func parseAirportLocalTime(airportCode, datetimeStr string) (*time.Time, error) {
	location, ok := memory.GetTimeZoneByAirportCode(airportCode)
	if !ok {
		return nil, errors.New(fmt.Sprintf("机场[%s]获取时区失败", airportCode))
	}
	t, err := time.ParseInLocation("2006-01-02 15:04", datetimeStr, location)
	if err != nil {
		return nil, err
	}
	return &t, nil
}

// GetBirthdayDateByIdCard 根据IdCard获取年月日
func GetBirthdayDateByIdCard(cardId string) (birthdayDate string) {
	birthday := ""
	// 兼容第一代15位身份证号码
	if len(cardId) == 15 {
		// 第一代身份证年份都是19开头的
		birthday = fmt.Sprintf("19%s", cardId[6:12])
	} else {
		birthday = cardId[6:14]
	}
	if birthday != "" {
		birthdayDate = birthday[0:4] + "-" + birthday[4:6] + "-" + birthday[6:]
	}
	return
}

func IsDateFormatCorrect(date string) bool {
	_, err := time.Parse("2006-01-02", date)
	return err == nil
}

func SplitTravelDates(dates string, forbiddenDate string) ([]string, [][]string) {
	if len(dates) == 0 {
		return []string{}, [][]string{}
	}

	datePairs := strings.Split(dates, "/")
	var allowedDates []time.Time
	for _, item := range datePairs {
		datePair := strings.Split(item, ">")
		beginDate, _ := time.Parse("2006-01-02", datePair[0])
		endDate, _ := time.Parse("2006-01-02", datePair[1])
		for beginDate.Before(endDate) || beginDate.Equal(endDate) {
			if slices.IndexFunc(allowedDates, func(t time.Time) bool {
				return beginDate.Equal(t)
			}) < 0 {
				allowedDates = append(allowedDates, beginDate)
			}
			beginDate = beginDate.AddDate(0, 0, 1)
		}
	}
	if len(forbiddenDate) > 0 {
		forbiddenDatePairs := strings.Split(forbiddenDate, "/")
		for _, item := range forbiddenDatePairs {
			forbiddenDatePair := strings.Split(item, ">")
			beginDate, _ := time.Parse("2006-01-02", forbiddenDatePair[0])
			endDate, _ := time.Parse("2006-01-02", forbiddenDatePair[1])
			allowedDates = slices.DeleteFunc(allowedDates, func(date time.Time) bool {
				return date.Before(endDate.AddDate(0, 0, 1)) && date.After(beginDate.AddDate(0, 0, -1))
			})
		}
	}
	sort.Slice(allowedDates, func(i, j int) bool {
		return allowedDates[i].Before(allowedDates[j])
	})

	dateRange := []string{allowedDates[0].Format(time.DateOnly), allowedDates[len(allowedDates)-1].Format(time.DateOnly)}
	var excludeDateRanges [][]string
	for index, date := range allowedDates {
		if index > 0 {
			if date.Equal(allowedDates[index-1].AddDate(0, 0, 1)) == false {
				excludeDateRanges = append(excludeDateRanges, []string{
					allowedDates[index-1].AddDate(0, 0, 1).Format(time.DateOnly),
					date.AddDate(0, 0, -1).Format(time.DateOnly),
				})
			}
		}
	}

	return dateRange, excludeDateRanges
}

func IsValidIPss(c *gin.Context) string {

	ip := c.ClientIP()
	xForwardedFor := c.Request.Header.Get("X-Forwarded-For")
	if xForwardedFor != "" {
		// 如果X-Forwarded-For存在，则直接使用第一个IP（通常是真实IP）
		ip = strings.Split(xForwardedFor, ",")[0]
	}
	return ip
}

func IsValidName(name string) bool {
	// 正则表达式匹配中文姓名
	reg := regexp.MustCompile(`^[\p{Han}{·}]+$`)
	return reg.MatchString(name)
}

// 验证身份证号码是否有效
func IsValidID(id string) (int, bool) {
	// 正则表达式匹配18位身份证号码
	re := regexp.MustCompile(`^\d{17}(\d|X|x)$`)
	if !re.MatchString(id) {
		return 0, false
	}

	// 省份代码
	var provinceCode = []int{11, 12, 13, 14, 15, 21, 22, 23, 31, 32, 33, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 71, 81, 82, 91}
	// 前两位数字必须在省份代码列表中
	if _, err := strconv.Atoi(string(id[:2])); err != nil || !contains(provinceCode, id[:2]) {
		return 0, false
	}

	// 计算校验码
	var sum int
	for i := 0; i < 17; i++ {
		num, _ := strconv.Atoi(string(id[i]))
		sum += num * weights[i]
	}
	mod := sum % 11

	// 校验码对应值
	checkCode := []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
	if string(checkCode[mod]) != strings.ToUpper(string(id[17])) {
		return 0, false
	}

	birthYear, birthMonth, birthDay := id[6:10], id[10:12], id[12:14]
	// 将字符串转换为整数
	birthYearInt, _ := strconv.Atoi(birthYear)
	birthMonthInt, _ := strconv.Atoi(birthMonth)
	birthDayInt, _ := strconv.Atoi(birthDay)

	// 获取当前日期
	today := time.Now()
	// 计算年龄
	age := today.Year() - birthYearInt
	// 如果生日还没到，年龄减1
	if today.Month() < time.Month(birthMonthInt) || (today.Month() == time.Month(birthMonthInt) && today.Day() < birthDayInt) {
		age--
	}

	return age, true
}

// weights 是计算校验码时使用的权重
var weights = []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}

// contains 检查列表中是否包含给定的字符串
func contains(list []int, str string) bool {
	for _, v := range list {
		if strconv.Itoa(v) == str {
			return true
		}
	}
	return false
}
